#ifndef ABSTRACTSLAVETASK
#define ABSTRACTSLAVETASK

/*!
 * \file AbstractSlaveTask.h
 * \author aimery aviles / thomas raynal
 * \version 2.0
 */


#include "TaskResult.h"
#include "AbstractTask.h"
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include  "Utils.h"
#include <time.h>
#include <stdlib.h>
#include <string>


/*! \namespace Network
 * 
 * Group master/slave task template & task handling utilities (trees & graphs)
 */
namespace MasterWorkerFramework
{

/*! \class AbstractGridSlaveTask
* \brief Model for slave tasks implementation
*/
class AbstractGridSlaveTask: public AbstractTask,public boost::enable_shared_from_this<AbstractGridSlaveTask> {
public:

	typedef boost::function<void(TaskResult*)> joinFunction;
 
	AbstractGridSlaveTask (char* n)
	{
		name_ = new std::string();
		*name_ =n;
		hash_ = new std::string(GetRandomString()); 
		parentTask_ = NULL;
		done_ = false;
		iteration_=1;
		bindedResults_ = new std::vector<TaskResult*>();
		statut_ = TASK_STATUT::PENDING;
	}

	/*!
	*  \brief Get the name of the slave task
	*
	*/
	virtual std::string* GetSlaveTaskName()=0;

	/*!
	*  \brief Execute the task
	*
	*/
	virtual void Execute()=0;

	/*!
	*  \brief Get the result type
	*
	*/
	virtual VALUE_TYPE GetTaskType()=0;

	std::string* GetName(){return name_;}
	std::string* GetHash(){return hash_;}


	void SetResult(TaskResult* r){result_ =r;}
	TASK_STATUT GetStatut(){return statut_;}
	void AppendResult(TaskResult* r){bindedResults_->push_back(r);}
	TaskResult* GetResult(){return result_;}

	/*!
	*  \brief Get the task dependency
	*
	*/
	AbstractGridSlaveTask* GetParent(){return parentTask_;}

	inline void operator<=(unsigned iteration){iteration_ = iteration;}
	inline bool operator==(AbstractGridSlaveTask& task){
		if (task.GetHash()==GetHash())
			return true;
		return false;
	}

	/*!
	*  \brief Get the task binded results
	*
	*/
	std::vector<TaskResult*>* GetBindedResult ()
	{
		return bindedResults_;
	}

	/*!
	*  \brief Set the binded completion function
	*
	*/
	AbstractGridSlaveTask& BindTaskCompleted(AbstractGridSlaveTask* bindedTask)
	{
		parentTask_=bindedTask;
		slaveTaskCompletionFunction_ = boost::bind(&AbstractGridSlaveTask::AppendResult,bindedTask,_1);//result);
		return *this;
	}

	void Join()
	{
		done_ = true;
		statut_ = TASK_STATUT::COMPLETED;

		if (!slaveTaskCompletionFunction_==NULL)
		{
			slaveTaskCompletionFunction_(result_);
		}	
	}

	~AbstractGridSlaveTask()
	{
		delete result_;
		delete bindedResults_;
		delete name_;
		delete hash_;
	}
	

protected:
	unsigned iteration_;
	joinFunction slaveTaskCompletionFunction_;
	AbstractGridSlaveTask* parentTask_;
	TaskResult* result_;
	std::vector<TaskResult*>* bindedResults_;
	std::string* name_;
	std::string* hash_;
	bool done_;
	TASK_STATUT statut_;
};

}
#endif